/**
 * Author(s): xuming.Wong <xuming.Wong@gmail.com>
 */

#ifndef __G_SPRITE_MANAGER_H__
#define __G_SPRITE_MANAGER_H__

#include "NgPrerequisites.h"
#include "OgreRenderQueueListener.h"

namespace PQEngine
{
	class SceneObject;
	class Sprite2D
	{
	public:
		typedef std::vector<Sprite2D*> SpriteList;
	private:
		static SpriteList _list;
		int _id;
	protected:
		Sprite2D()
			: x1(-1),x2(1),y1(1),y2(-1),tx1(0),tx2(0),ty1(1),ty2(1)
		{
		}

		/*Sprite to be sent to the screen at render time.
		@remark
		Sprite coordinates are in screen space: top left pixel is (-1, 1), and bottom right
		is (1, -1). The texture space, instead, ranges from (0, 0) to (1, 1).
		@param id Auto generated int ID
		@param tex Ogre texture pointer
		@param x1 x coordinate for the top left point in the sprite.
		@param y1 y coordinate for the top left point in the sprite.
		@param x2 x coordinate for the bottom right point in the sprite.
		@param y2 y coordinate for the bottom right point in the sprite.
		@param tx1 u coordinate for the texture, in the top left point of the sprite.
		@param ty1 v coordinate for the texture, in the top left point of the sprite.
		@param tx2 u coordinate for the texture, in the bottom right point of the sprite.
		@param ty2 u coordinate for the texture, in the bottom right point of the sprite.
		*/
		Sprite2D(int id,Ogre::Texture* tex,float pt1x,float pt1y,float pt2x,float pt2y,
			float pt1tx=0,float pt1ty=0,float pt2tx=1,float pt2ty=1)
			: _id(id), x1(pt1x),x2(pt2x),y1(pt1y),y2(pt2y),tx1(pt1tx),tx2(pt2tx),ty1(pt1ty),ty2(pt2ty)
		{
			texHandle=tex->getHandle();
		}
	public:
		inline static Sprite2D* create(Ogre::Texture* tex,float pt1x,float pt1y,float pt2x,float pt2y,
			float pt1tx=0,float pt1ty=0,float pt2tx=1,float pt2ty=1)
		{
			Sprite2D* sprite=new Sprite2D(_list.size(),tex,pt1x,pt1y,pt2x,pt2y);
			_list.push_back(sprite);
			return sprite;
		}

		inline Sprite2D* get(int id)
		{
			if(id<0||id>=_list.size()){
				return 0;
			}
			return _list[id];

		}


	   float x1, y1, x2, y2;// sprite coordinates
	   float tx1, ty1, tx2, ty2;// texture coordinates
	   Ogre::ResourceHandle texHandle;// texture handle
	};

	struct VertexChunk {
	   Ogre::ResourceHandle texHandle;
	   Ogre::uint vertexCount;
	};

	class SpriteManager
		: public Ogre::RenderQueueListener
	{
	public:
		typedef std::vector<Sprite2D*> SpriteList;
		static const int MIN_HARD_BUF_SIZE=120;
	public:
		/*Construct this sprite manager and
		registers it as OGRE render queue listener.
		*/
		SpriteManager(SceneObject* sceneObject, unsigned char targetQueue=Ogre::RENDER_QUEUE_OVERLAY, bool afterQueue=true);
		virtual ~SpriteManager();

		//implement OGRE render queue listeners
		virtual void renderQueueStarted(unsigned char queueGroupId, const Ogre::String &invocation, bool &skipThisInvocation);
		virtual void renderQueueEnded(unsigned char queueGroupId, const Ogre::String &invocation, bool &repeatThisInvocation);

		void addSprite(Sprite2D* sprite);

	private:
		/*Render all the 2d data stored in the hardware buffers.
		*/
		void renderBuffer();

		/**Create a new hardware buffer
			@param size Vertex count for the new hardware buffer.
		*/
		void createHardwareBuffer(Ogre::uint size);
		//Destroy the hardware buffer
		void destroyHardwareBuffer();
		// Set OGRE for rendering
		void prepareForRender();

	private:
		SceneObject* _sceneObject;//the owner scene
		
		Ogre::SceneManager* _sceneManager;
		Ogre::RenderOperation _renderOperation;
		Ogre::HardwareVertexBufferSharedPtr _hardwareBuffer;
		unsigned char _targetQueue;
		bool _afterQueue;

		SpriteList _sprites;
	}; 
}
#endif

